# -*- coding: utf-8 -*-
import logging
import concurrent.futures
import os
import re

import requests

from django.db.models import Q
from django.conf import settings
from django.core.management.base import BaseCommand, CommandError

from common.models import ViewModel, SiteTaxonomy

from book import dao
from common import dao as common_dao

logger = logging.getLogger('book.book_dl')


class Command(BaseCommand):
    help = 'download file'
    s = None
    host = 'http://www.allitebooks.com'
    UA = 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:57.0) ' \
        'Gecko/20100101 Firefox/57.0'

    log = logging.getLogger('book.book_dl')

    def add_arguments(self, parser):
        parser.add_argument('--start', type=int, default=1,
                            help='start page num')
        parser.add_argument('--end', type=int, default=3, help='end page num')
        parser.add_argument('--size', type=int, default=100, help='page size')
        parser.add_argument('--c', type=int, default=4,
                            help='concurrent workers count')
        parser.add_argument('--m', type=str, default='thread',
                            help='concurrent workers count')
        parser.add_argument('site', type=str)

    def get_r(self, url, allow_redirects=False):
        if not self.s:
            self.s = requests.Session()
        r = self.s.get(url, allow_redirects=allow_redirects, headers={
            'Referer': self.host,
            'User-Agent': self.UA})
        return r

    def get_content(self, url):
        self.log.debug('GET  ' + url)
        r = self.get_r(url, allow_redirects=True)
        html = r.content
        self.log.debug('GET  %s %s', url, r.status_code)
        r.raise_for_status()
        return html

    def download_cover(self, url, file_path):
        file_dir = os.path.dirname(file_path)
        if not os.path.exists(file_dir):
            os.makedirs(file_dir)
        try:
            with open(file_path, 'wb') as fd:
                fd.write(self.get_content(url))
            return True
        except requests.exceptions.HTTPError:
            self.log.exception('download image failed')
        return False

    def handle_page(self, site, page_no):
        books = dao.get_books(site.id, page_no, self.page_size)
        prefix = None
        if site.name == 'allitebooks':
            prefix = 'http://www.allitebooks.com/wp-content/uploads'
        elif site.name == 9:
            prefix = 'http://s.it-ebooks-api.info/'
        elif site.name == 'ireadweek':
            prefix = 'http://www.ireadweek.com/Administrator/Res/Uploads/book/'

        if not prefix:
            return
        for book in books:
            if book.cover_url.startswith('http'):
                file_path = re.sub(
                    prefix, '', book.cover_url, flags=re.IGNORECASE)
                logger.debug(file_path)
                file_path = os.path.join(
                    'cover', os.path.join(*(file_path.split('/'))))
                logger.debug(file_path)
                full_path = os.path.join(settings.STATIC_ROOT, file_path)
                if self.download_cover(book.cover_url, full_path):
                    if os.path.exists(full_path):
                        dao.update_book_cover(
                            book, file_path.replace('\\', '/'))
            else:
                logger.debug('skip %s', book.cover_url)

    def handle(self, *args, **options):
        start = options['start']
        end = options['end']
        c = options['c']
        m = options['m']
        logger.debug('start:%d end:%d c:%d' % (start, end, c))
        executor_class = None
        site_q = options['site']
        # site = common_dao.find_site_by(Q(id=site_q) | Q(name=site_q))
        site = common_dao.find_site_by(name=site_q)
        if not site:
            logger.error('can not find site info by : %s',site_q)
            return
        self.page_size = options['size']
        if m == 'thread':
            executor_class = concurrent.futures.ThreadPoolExecutor
        elif m == 'process':
            executor_class = concurrent.futures.ProcessPoolExecutor
        else:
            self.stdout.write(self.style.error('invalid mode %s' % (m,)))
            return
        pages = range(start, end + 1)
        with executor_class(max_workers=c) as executor:
            future_to_url = {executor.submit(
                self.handle_page, site, page): page for page in pages}
            for future in concurrent.futures.as_completed(future_to_url):
                url = future_to_url[future]
                future.result()
                logger.debug('OK   %s' % (url, ))
